package cn.buk.tms.train.service;

import cn.buk.common.JsonResult;
import cn.buk.qms.SmsUtil;
import cn.buk.tms.dto.TrainOrderDto;
import cn.buk.tms.dto.TrainOrderPassengerDto;
import cn.buk.qms.service.BaseOrderService;
import cn.buk.tms.entity.bill.BillInfo;
import cn.buk.tms.entity.config.EnterpriseConfig;
import cn.buk.tms.entity.misc.*;
import cn.buk.tms.entity.order.OrderNoInfo;
import cn.buk.tms.entity.order.train.TrainOrder;
import cn.buk.tms.entity.order.train.TrainOrderPassenger;
import cn.buk.tms.train.dao.TrainOrderDao;
import cn.buk.tms.train.sc.TrainOrderSearchCriteria;
import cn.buk.tms.util.ValidationUtils;
import cn.buk.common.util.CheckUtil;
import cn.buk.common.util.DateUtil;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.annotation.Secured;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.FileInputStream;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @author yfdai
 */
@Component
public class TrainOrderServiceImpl extends BaseOrderService implements TrainOrderService {

    private static final Logger logger = LogManager.getLogger(TrainOrderServiceImpl.class);

    private static final String TRAIN_ORDER_SMS_TEMPLATE = "%s%s，车票已预订成功，订单号%s，请尽快去换取纸质车票。";

    @Autowired
    private TrainOrderDao trainOrderDao;

    /**
     * 搜索订单
     * @param enterpriseId
     * @param sc
     * @return
     */
    @Override
    public List<TrainOrderDto> searchTrainOrders(int enterpriseId, int userId, TrainOrderSearchCriteria sc) {
        List<Integer> allowedCustomerIds = searchAllowedCustomerIds(enterpriseId, userId);

        if(isOnlySeeOwn(enterpriseId, userId)) {
            //只能看自己的订单
            User user = userDao.getUserById(userId);
            final String username = user.getUsername();
            sc.setOp1(username);
        }

        List<TrainOrder> orders = trainOrderDao.searchTrainOrders(enterpriseId, sc, allowedCustomerIds);

        final boolean needHideCustomerName = isNeedHideCustomerName(enterpriseId, userId);
        User user = userDao.getUserById(userId);

        List<TrainOrderDto> dtos = new ArrayList<>();
        for(TrainOrder order: orders) {
            maskCustomerName(order.getCustomer(), order.getOperator(), user.getUsername(), needHideCustomerName);
            dtos.add(TrainOrderDto.createByTrainOrder(order));
        }

        return dtos;
    }

    /**
     * 获取订单详情
     * @param enterpriseId
     * @param userId
     * @param orderId
     * @return
     */
    @Override
    public TrainOrderDto getTrainOrderById(final int enterpriseId, int userId, final int orderId) {
        TrainOrder o = trainOrderDao.getTrainOrderById(orderId);

        if (o == null || o.getEnterpriseId() != enterpriseId) {
          return null;
        } else {
            //是否要对当前用户隐藏客户名称
            if (isNeedHideCustomerName(enterpriseId, userId)) {
                User user = userDao.getUserById(userId);
                maskCustomerName(o.getCustomer(), o.getOperator(), user.getUsername(), true);
            }
            return TrainOrderDto.createByTrainOrder(o);
        }
    }

    /**
     * 创建订单
     * @param enterpriseId
     * @param dto
     * @return
     */
    @Override
    public JsonResult createTrainOrder(final int enterpriseId, final String username, TrainOrderDto dto) {
        dto.processPassengerInfo();
        try {
            ValidationUtils.validate(dto);
            for(TrainOrderPassengerDto psgDto: dto.getPassengers()) {
                ValidationUtils.validate(psgDto);
            }
        } catch (Exception e) {
            logger.error(e.getMessage());

            return JsonResult.createJsonResult(-1, e.getMessage());
        }

        dto.setEnterpriseId(enterpriseId);
        dto.setOperator(username);

        TrainOrder trainOrder = TrainOrderDto.convertToTrainOrder(dto);

        // 订单号
        trainOrder.setOrderNo(orderNoGenerator.generateOrderNo(enterpriseId, OrderNoInfo.ORDER_TRAIN));

        try {
            int retCode = trainOrderDao.createTrainOrder(trainOrder);
            return JsonResult.createJsonResult(retCode);
        } catch (RuntimeException ex) {
            logger.error(ex.getMessage());
            return JsonResult.createJsonResult(-100, ex.getMessage());
        }
    }

    /**
     * 修改酒店订单的备注
     * @param enterpriseId
     * @param username
     * @param orderId
     * @param remark
     * @return
     */
    @Override
    public JsonResult updateTrainOrderRemark(int enterpriseId, String username, int orderId, String remark) {
        try {
            int retCode = trainOrderDao.updateTrainOrderRemark(enterpriseId, username, orderId, remark);
            return JsonResult.createJsonResult(retCode);
        } catch (RuntimeException ex) {
            return JsonResult.createJsonResult(-100, ex.getMessage());
        }
    }

    @Override
    public JsonResult updateTrainOrderExternalOrderNo(int enterpriseId, String username, int orderId, String externalOrderNo) {
        try {
            int retCode = trainOrderDao.updateTrainOrderExternalOrderNo(enterpriseId, username, orderId, externalOrderNo);
            return JsonResult.createJsonResult(retCode);
        } catch (RuntimeException ex) {
            return JsonResult.createJsonResult(-100, ex.getMessage());
        }
    }

    /**
     * 修改酒店订单的供应商
     * @param enterpriseId
     * @param username
     * @param orderId
     * @param supplierId
     * @return
     */
    @Override
    public JsonResult updateTrainOrderSupplier(int enterpriseId, String username, int orderId, int supplierId) {
        try {
            int retCode = trainOrderDao.updateTrainOrderSupplier(enterpriseId, username, orderId, supplierId);
            return JsonResult.createJsonResult(retCode);
        } catch (RuntimeException ex) {
            return JsonResult.createJsonResult(-100, ex.getMessage());
        }
    }

    /**
     * 修改酒店订单的支付方式
     * @param enterpriseId
     * @param username
     * @param orderId
     * @param paymentMethodId
     * @return
     */
    @Override
    public JsonResult updateTrainOrderPaymentMethod(int enterpriseId, String username, int orderId, int paymentMethodId) {
        try {
            int retCode = trainOrderDao.updateTrainOrderPaymentMethod(enterpriseId, username, orderId, paymentMethodId);
            return JsonResult.createJsonResult(retCode);
        } catch (RuntimeException ex) {
            return JsonResult.createJsonResult(-100, ex.getMessage());
        }
    }

    /**
     * 修改酒店订单的价格
     * @param enterpriseId
     * @param username
     * @param orderId
     * @param price
     * @param cost
     * @param serviceCharge
     * @return
     */
    @Override
    public JsonResult updateTrainOrderPrice(int enterpriseId, String username, int orderId, double price, double cost, double serviceCharge) {
        TrainOrder trainOrder = trainOrderDao.getTrainOrderById(orderId);
        if (trainOrder.getStatus() == TrainOrder.STATUS_DONE || trainOrder.getStatus() == TrainOrder.STATUS_CANCELED) {
            return JsonResult.createJsonResult(-1, "价格已不能修改");
        }

        TrainOrderDto dto = TrainOrderDto.createByTrainOrder(trainOrder);
        dto.setPrice(price);
        dto.setCost(cost);
        dto.setServiceCharge(serviceCharge);
        dto.calc();

        int retCode = trainOrderDao.updateTrainOrderPrice(enterpriseId, username, orderId, price, cost, serviceCharge,
                dto.getTotalAmount(), dto.getTotalCost(), dto.getProfit());
        return JsonResult.createJsonResult(retCode);
    }

    /**
     * 修改乘车人信息
     */
    @Override
    public JsonResult updateTrainOrderPassenger(int enterpriseId, String username, int orderId, TrainOrderPassengerDto psgDto) {
        TrainOrder trainOrder = trainOrderDao.getTrainOrderById(orderId);
        if (trainOrder.getStatus() == TrainOrder.STATUS_DONE || trainOrder.getStatus() == TrainOrder.STATUS_CANCELED) {
            return JsonResult.createJsonResult(-1, "已不能修改");
        }

        int retCode = trainOrderDao.updateTrainOrderPassenger(enterpriseId, username, orderId, psgDto);
        return JsonResult.createJsonResult(retCode);
    }

    /**
     * 开始处理订单
     * @param enterpriseId
     * @param username
     * @param orderId
     * @return
     */
    @Override
    public JsonResult processTrainOrder(final int enterpriseId, final String username, final int orderId) {
        //核对信用额度是否足够
        TrainOrder orderInfo = trainOrderDao.getTrainOrderById(orderId);
        if (orderInfo == null || orderInfo.getEnterpriseId() != enterpriseId) {
            return JsonResult.createJsonResult(-404, "不存在");
        }

        if (orderInfo.getCustomer() != null && orderInfo.getCustomer().getCustomerEnterpriseId() >0) {
            //该客户可以判断授信额度
            final double totalAmount = orderInfo.getTotalAmount();
            final int customerEnterpriseId = orderInfo.getCustomer().getCustomerEnterpriseId();
            if (isOverCreditLimit(enterpriseId, customerEnterpriseId, totalAmount)) {
                return JsonResult.createJsonResult(-100, "订单金额(" + totalAmount + ")大于可用额度");
            }
        }

        try {
            int retCode = trainOrderDao.processTrainOrder(enterpriseId, username, orderId);
            return JsonResult.createJsonResult(retCode);
        } catch (RuntimeException ex) {
            return JsonResult.createJsonResult(-100, ex.getMessage());
        }
    }

    /**
     * 火车票订单处理完毕
     * @param enterpriseId
     * @param username
     * @param orderId
     * @param remark
     * @return
     */
    @Override
    public JsonResult finishTrainOrder(int enterpriseId, String username, int orderId, String remark) {

        TrainOrder trainOrder = trainOrderDao.getTrainOrderById(orderId);
        if (trainOrder.getSupplier() == null || trainOrder.getPaymentMethod() == null) {
            return JsonResult.createJsonResult(-1, "供应商、支付方式需要设置");
        }

        int retCode = 0;
        try {
            retCode = trainOrderDao.finishTrainOrder(enterpriseId, username, orderId, remark);
        } catch (RuntimeException ex) {
            return JsonResult.createJsonResult(-100, ex.getMessage());
        }

        if (retCode == 1) {
            //导入账单
            importService.importTrainOrder(enterpriseId, username, orderId);
        }

        return JsonResult.createJsonResult(retCode);
    }

    @Override
    public List<OperationLog> searchTrainOrderHistory(int enterpriseId, int orderId) {
        return trainOrderDao.searchTrainOrderHistory(enterpriseId, orderId);
    }

    /**
     * 取消酒店订单
     * @param enterpriseId
     * @param username
     * @param orderId
     * @param remark
     * @return
     */
    @Override
    public JsonResult cancelTrainOrder(int enterpriseId, String username, int orderId, String remark) {
        try {
            int retCode = trainOrderDao.cancelTrainOrder(enterpriseId, username, orderId, remark);
            return JsonResult.createJsonResult(retCode);
        } catch (RuntimeException ex) {
            return JsonResult.createJsonResult(-100, ex.getMessage());
        }
    }

    /**
     * 回滚酒店订单的状态
     * @param enterpriseId
     * @param username
     * @param orderId
     * @return
     */
    @Override
    @Secured({RoleInfo.ROLE_ADMIN, RoleInfo.ROLE_SUPERVISOR})
    public JsonResult rollbackTrainOrder(final int enterpriseId, final String username, final int orderId, final String remark) {
        if (remark == null || remark.trim().length() < 2) {
          return JsonResult.createJsonResult(-10, "请输入理由");
        }

        TrainOrder trainOrder = trainOrderDao.getTrainOrderById(orderId);
        if (trainOrder == null || trainOrder.getEnterpriseId() != enterpriseId) {
            return JsonResult.createJsonResult(-1, "订单不存在");
        }

        if (trainOrder.getStatus() != TrainOrder.STATUS_DONE) {
            return JsonResult.createJsonResult(-2, "订单状态不是完成状态。");
        }

        List<BillInfo> billInfos = billService.searchBillInfoByOrderNo(enterpriseId, trainOrder.getOrderNo());
        if (!billInfos.isEmpty()) {
            doSendAlert(enterpriseId, "订单(" + trainOrder.getOrderNo() + ")回滚失败，存在对应的账单", null, EntDepartment.DEPT_ADMINISTRATOR);
            return JsonResult.createJsonResult(-2, "存在对应的账单，不能回滚");
        }

        int retCode = trainOrderDao.rollbackTrainOrder(enterpriseId, username, orderId, remark);
        if (retCode > 0) {
            doSendAlert(enterpriseId, "火车票订单(" + trainOrder.getOrderNo() + ")已回滚: " + remark, null, EntDepartment.DEPT_ADMINISTRATOR);
        }

        return JsonResult.createJsonResult(retCode);
    }

    @Override
    public JsonResult getTrainOrderOrderSmsContent(int enterpriseId, String username, int orderId, int psgId, int smsFormat) {
        TrainOrder order = trainOrderDao.getTrainOrderById(orderId);
        String smsContent = generateSmsContent(enterpriseId, username, order, psgId, smsFormat);
        if (smsContent != null) {
            return JsonResult.createJsonResult(1, smsContent);
        } else {
            return JsonResult.createJsonResult(-1, "无法生成短信内容");
        }
    }

    @Override
    public JsonResult sendTrainOrderOrderSmsContent(int enterpriseId, String username, int orderId, int psgId, String mobileNo0, int smsFormat, String smsContent0) {
        if (mobileNo0.length() > 0 && !CheckUtil.isMobileNo(mobileNo0)) {
            return JsonResult.createJsonResult(-1, "输入的手机号不符合格式要求");
        }

        TrainOrder trainOrder = trainOrderDao.getTrainOrderById(orderId);

        TrainOrderPassenger psgInfo = null;
        for(TrainOrderPassenger psg: trainOrder.getPassengers()) {
            if (psgId == psg.getId()) {
                psgInfo = psg;
                break;
            }
        }
        if (psgInfo == null) {
          return JsonResult.createJsonResult(-2, "无指定乘机人");
        }

        String mobileNo = CheckUtil.isMobileNo(mobileNo0) ? mobileNo0: psgInfo.getMobile();
        if (!CheckUtil.isMobileNo(mobileNo)) {
            return JsonResult.createJsonResult(-3, "无符合要求的手机号");
        }

        TrainOrder order = trainOrderDao.getTrainOrderById(orderId);

        String smsContent = smsContent0 == null || smsContent0.trim().length() == 0 ? generateSmsContent(enterpriseId, username, order, psgId, smsFormat) : smsContent0;

        SmsDetail smsDetail = SmsDetail.createSmsDetail(enterpriseId, username, mobileNo, smsContent, order.getOrderNo());


        return sendSms(smsDetail);
    }

  @Override
  public JsonResult createTrainOrderByExcel(int enterpriseId, String username, String fileName,
      int supplierId, int paymentMethodId) {
      List<TrainOrderDto> list = new ArrayList<>();

      try {
          File target = new File(fileName);
          FileInputStream fi = new FileInputStream(target);
          Workbook wb = create(fi);

          generateTrainOrdersFromExcel(enterpriseId, list, wb);
      } catch (Exception ex) {
          logger.error(ex.getMessage());
      }

      if (list.isEmpty()) {
          return JsonResult.createJsonResult(-1, "没有数据");
      }

      Supplier supplier = new Supplier();
      supplier.setId(supplierId);

      PaymentMethod pm = new PaymentMethod();
      pm.setId(paymentMethodId);

      List<TrainOrder> orders = new ArrayList<>();
      for(TrainOrderDto dto: list) {
          dto.processPassengerInfo();
          dto.calc();

          TrainOrder o = TrainOrderDto.convertToTrainOrder(dto);

          o.setOperator(username);
          o.setSupplier(supplier);
          o.setPaymentMethod(pm);

          orders.add(o);
      }


      int retCode = trainOrderDao.createTrainOrders(orders);

      return JsonResult.createJsonResult(retCode);
  }

  @Override
  public void autoAlertTrainOrderStatus() {
      final int enterpriseId = 5;
      TrainOrderSearchCriteria sc = new TrainOrderSearchCriteria();
      sc.setStatus(0);
      sc.setPageSize(1000);

      List<TrainOrder> orders = trainOrderDao.searchTrainOrders(enterpriseId, sc, null);

      if (!orders.isEmpty()) {
          doSendAlert(enterpriseId, "有" + orders.size() + "个火车票订单待处理", null, EntDepartment.DEPT_TICKETING);
      }
  }

  private void generateTrainOrdersFromExcel(final int enterpriseId, List<TrainOrderDto> list,
        Workbook wb) {
        Sheet sheet = wb.getSheetAt(0);
        final int rowNum = sheet.getLastRowNum() + 1;

        int dataCount = 0;
        for (int i = 1; i < rowNum; i++) {
            Row row = sheet.getRow(i);
            dataCount++;

            //客户名称
            final String customerName = row.getCell(0).getStringCellValue().trim();
            if (customerName.length() == 0) {
                logger.warn("Customer name is null.");
                continue;
            }

            //使用企业名称查找客户，需要完全匹配
            List<Customer> customers = customerDao.searchCustomerByCustomerName(enterpriseId, customerName);
            if (customers.size() != 1) {
                logger.warn("Customer not matched.");
                continue;
            }

            //
            TrainOrderDto o = new TrainOrderDto();
            o.setEnterpriseId(enterpriseId);
            o.setOrderNo(orderNoGenerator.generateOrderNo(enterpriseId, OrderNoInfo.ORDER_TRAIN));
            o.setCustomerId(customers.get(0).getId());

            //外部订单号
            final String externalOrderNo = row.getCell(1).getStringCellValue().trim();
            o.setExternalOrderNo(externalOrderNo);

            //车次
            final String trainNo = row.getCell(2).getStringCellValue().trim();
            o.setTrainNo(trainNo);

            //出发
            final String dcity = row.getCell(3).getStringCellValue().trim();
            o.setDcity(dcity);

            //到达
            final String acity = row.getCell(4).getStringCellValue().trim();
            o.setAcity(acity);

            //出发时间
            final String strDdate = row.getCell(5).getStringCellValue().trim();
            try {
                o.setDdate(DateUtil.convertToDate(strDdate.substring(0, 10), "yyyy-MM-dd"));
                o.setDtime(strDdate.substring(11).trim());
            } catch (ParseException e) {
                e.printStackTrace();
            }

            final String strAdate = row.getCell(6).getStringCellValue().trim();
            o.setAtime(strAdate.substring(11).trim());


            TrainOrderPassengerDto psgInfo = new TrainOrderPassengerDto();
            o.getPassengers().add(psgInfo);

            final String psgName = row.getCell(7).getStringCellValue().trim();
            psgInfo.setName(psgName);

            final String status = row.getCell(8).getStringCellValue().trim();
            o.setRemark(status);

            final String seatClass = row.getCell(9).getStringCellValue().trim();
            o.setSeatClass(seatClass);

            final double cost = row.getCell(10).getNumericCellValue();
            o.setCost(cost);

            final double price = row.getCell(11).getNumericCellValue();
            o.setPrice(price);



            final String mobileNo = getStringValue(row, 12, null);
            psgInfo.setMobile(mobileNo);

            final String couchNo = getStringValue(row, 13, null);
            psgInfo.setCoachNo(couchNo);

            final String seatNo = getStringValue(row, 14, null);
            psgInfo.setSeatNo(seatNo);

            final String costCenter = getStringValue(row, 15, null);
            o.setCostCenter(costCenter);


            list.add(o);
        }

        if (list.size() != dataCount) {
            list.clear();
        }
    }

    private String getStringValue(final Row row, final int column, final String timeFormat) {
        Cell cell = row.getCell(column);
        if (cell == null) {
            return null;
        }

        switch (cell.getCellType()) {
            case NUMERIC:
                if (org.apache.poi.ss.usermodel.DateUtil.isCellDateFormatted(cell)) {
                    //如果是date类型则 ，获取该cell的date值
                    Date date = org.apache.poi.ss.usermodel.DateUtil.getJavaDate(cell.getNumericCellValue());
                    SimpleDateFormat format = new SimpleDateFormat(timeFormat);
                    return format.format(date);
                } else {// 纯数字
                    BigDecimal big= BigDecimal.valueOf(cell.getNumericCellValue());
                    return big.toString();
                }
            default:
                return cell.getStringCellValue();
        }
    }

    private String generateSmsContent(int enterpriseId, String username, TrainOrder order, int psgId, int smsFormat) {


        TrainOrderPassenger psgInfo = null;
        for(TrainOrderPassenger psg: order.getPassengers()) {
            if (psgId == psg.getId()) {
                psgInfo = psg;
                break;
            }
        }
        if (psgInfo == null) {
          return null;
        }

        return generateSmsContentByTemplate(enterpriseId, smsFormat, order, psgInfo);
    }

    private String generateSmsContentByTemplate(int enterpriseId, int smsFormat, TrainOrder order, TrainOrderPassenger psgInfo) {
        final String companySign =  doGetEntCfg(enterpriseId, EnterpriseConfig.API_SMS_COMPANY_SIGN);
        final String smsRouteInfo = SmsUtil.convertTrainOrder(order, psgInfo);

        String smsContent = null;
        if (smsFormat == 0) {
            smsContent = String.format(TRAIN_ORDER_SMS_TEMPLATE, companySign, smsRouteInfo, order.getExternalOrderNo());
        }

        return smsContent;
    }
}
